unit uThreads;
(*

  Unit that contains the thread classes that eConsole uses

*)

interface
Uses Windows,
     Messages,
     Classes,
     Forms,
     SysUtils,
     Graphics,

     uConstants,
     uActiveDesktop,
     uFakeLoad
     ;

Type CAsynchronousChildWaitThread = Class( TThread )
     (* Starts the process detached from the main window thread *)
       fChildHandle : THandle;
       fForm : TForm;
       fCommandline : String;
       Constructor Create( aParentForm : TForm; const aCommandline : String );
       Procedure Execute; override;
       Procedure ChildClosed;
     End;

Type CHandleWaitThread = Class( TThread )
     (* Waits for a (process) handle and notifies the parent *)
       fChildHandle : THandle;
       fForm : TForm;
       Constructor Create( aParentForm : TForm; aHandle : THandle );
       Procedure Execute; override;
       Procedure ChildClosed;
     End;

Type CBitmapThread = Class( TThread )
       fForm : TForm;
       fBitmap : TBitmap;
       Constructor Create( aParent : TForm );
     End;

Type CBitmapLoadThread = Class( CBitmapThread )
       fFilename : String;
       Constructor Create( aParent : TForm; const aFilename : String );
       Procedure Execute; override;
     End;

{
Type CTintBitmapThread = Class( CBitmapThread )
       Constructor Create( aParent : TForm; aSourceBitmap : TBitmap );
       Procedure Execute; override;
     End;
}
implementation

Constructor CAsynchronousChildWaitThread.Create;
Begin
  inherited Create( True );

  fForm := aParentForm;
  fCommandline := aCommandline;
  FreeOnTerminate := True;

  Resume;
End;

Procedure CAsynchronousChildWaitThread.ChildClosed;
Begin
  fForm.Perform( wm_ChildExit, 0, 0 );
End;

Procedure CAsynchronousChildWaitThread.Execute;
Var SA : TSecurityAttributes;
    Startup : TStartupInfo;
    Info : TProcessInformation;

    S : String;
    Comspec : String;

Begin
  Priority := tpHighest;

  FillChar( SA, SizeOf( SA ), 0 );
  SA.nLength := SizeOf( SA );
  SA.bInheritHandle := True;
  SA.lpSecurityDescriptor := nil;

  FillChar( Startup, SizeOf( Startup ), 0 );
  Startup.cb := SizeOf( Startup );
  S := 'eConsole command window ...';
  Startup.lpTitle := @S[1];

  SetLength( Comspec, 255 );
  GetEnvironmentVariable( 'COMSPEC', @Comspec[1], Length( Comspec ));

  {
  WriteLn('Starting "'+PChar( @Comspec[1] )+'"...');
  }
  If not CreateProcess( @Comspec[1],PChar( fCommandline ),nil,nil,True, 0, nil,nil, Startup, Info )
    then Synchronize( ChildClosed ) {RaiseLastWin32Error}
    else
      Begin
        fChildHandle := Info.hProcess;

        {WriteLn('Child watch thread goes to sleep ...');}
        Priority := tpLowest;
        WaitForSingleObject( fChildHandle, INFINITE );
        {WriteLn('Child watch thread notifies parent ...');}
        If not Terminated (* The parent does not know that we'll terminate ... *)
          then Synchronize( ChildClosed );
      End;
End;

Constructor CHandleWaitThread.Create;
Begin
  inherited Create( True );

  fForm := aParentForm;
  fChildHandle := aHandle;
  FreeOnTerminate := True;
  Priority := tpLowest;

  Resume;
End;

Procedure CHandleWaitThread.ChildClosed;
Begin
  fForm.Perform( wm_ChildExit, fChildHandle, 0 );
End;

Procedure CHandleWaitThread.Execute;
Begin
  {WriteLn('Synchronous child watch thread goes to sleep ...');}
  WaitForSingleObject( fChildHandle, INFINITE );
  {WriteLn('Synchronous child watch thread notifies parent ...');}
  If not Terminated (* The parent does not know that we'll terminate ... *)
    then Synchronize( ChildClosed );
End;

Constructor CBitmapThread.Create;
Begin
  inherited Create( True );
  FreeOnTerminate := True;
  fForm := aParent;
  fBitmap := nil;
End;

Constructor CBitmapLoadThread.Create;
Begin
  inherited Create( aParent );
  If FileExists( aFilename )
    then
      Begin
        fFilename := aFilename {+#0};
        {If Pos( 'BMP', aFilename ) > 0
          then Priority := tpHighest
          else Priority := tpLowest;}
        {Priority := tpHighest;}  
        Resume;
      End
    else fFilename := '';
End;

Procedure CBitmapLoadThread.Execute;
Begin
  (* This bitmap will be released by the main thread *)
  fBitmap := LoadImage( fFilename );

  If Assigned( fBitmap ) (* Some more sanity checks if we get a valid bitmap *)
    then
      Begin
        If fBitmap.Empty
          then
            Begin
              MessageBox( 0,PChar('Loading of "'+PChar(@fFilename[1])+'" failed.'), 'eConsole', idOK );
              fBitmap.Free;
              fBitmap := SafeBackground;
              WriteLn( 'Safe' );
            End;
      End
    else fBitmap := SafeBackground;

  If not Terminated and Assigned( fForm )
    then Postmessage( fForm.Handle, wm_UseBitmap, Integer( fBitmap ), 0 );
  fBitmap := nil;
End;

end.
